Micron Document
<!DOCTYPE html>
<html class="client-nojs vector-feature-language-in-header-enabled vector-feature-language-in-main-page-header-disabled vector-feature-page-tools-pinned-disabled vector-feature-toc-pinned-clientpref-0 vector-toc-not-available vector-feature-main-menu-pinned-disabled vector-feature-limited-width-clientpref-1 vector-feature-limited-width-content-enabled vector-feature-custom-font-size-clientpref-1 vector-feature-appearance-pinned-clientpref-0 skin-theme-clientpref-day vector-sticky-header-enabled" lang="de" dir="ltr"><head>
<meta charset="UTF-8">
<title>Off-by-one-Error</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/png" href="./_res_/favicon.png">
<link rel="canonical" href="https://de.wikipedia.org/wiki/Off-by-one-Error"> <link href="./_mw_/ext.cite.styles.css" rel="stylesheet" type="text/css">
<link href="./_mw_/ext.pygments.css" rel="stylesheet" type="text/css">
<link href="./_mw_/ext.wikimediamessages.styles.css" rel="stylesheet" type="text/css">
<link href="./_mw_/skins.vector.icons.css" rel="stylesheet" type="text/css">
<link href="./_mw_/skins.vector.search.codex.styles.css" rel="stylesheet" type="text/css">
<link href="./_mw_/skins.vector.styles.css" rel="stylesheet" type="text/css">
<meta name="ResourceLoaderDynamicStyles" content="">
<link href="./_mw_/ext.gadget.citeRef.css" rel="stylesheet" type="text/css">
<link href="./_mw_/ext.gadget.defaultPlainlinks.css" rel="stylesheet" type="text/css">
<link href="./_mw_/ext.gadget.dewikiCommonHide.css" rel="stylesheet" type="text/css">
<link href="./_mw_/ext.gadget.dewikiCommonLayout.css" rel="stylesheet" type="text/css">
<link href="./_mw_/ext.gadget.dewikiCommonStyle.css" rel="stylesheet" type="text/css">
<link href="./_mw_/ext.gadget.dewikiDarkmode.css" rel="stylesheet" type="text/css">
<link href="./_mw_/ext.gadget.dewikiResponsive.css" rel="stylesheet" type="text/css">
<link href="./_mw_/ext.gadget.specialSearch.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" type="text/css" href="./_mw_/site.styles.css">
<link rel="stylesheet" type="text/css" href="./_mw_/noscript.css">
<link rel="stylesheet" type="text/css" href="./_res_/footer.css">
<link rel="stylesheet" type="text/css" href="./_res_/vector-2022.css">
</head>
<body class="skin--responsive skin-vector skin-vector-search-vue mediawiki ltr sitedir-ltr mw-hide-empty-elt ns-0 ns-subject page-Off-by-one-Error rootpage-Off-by-one-Error skin-vector-2022 action-view">
<div class="mw-page-container">
<div class="mw-page-container-inner">
<div class="mw-content-container">
<main id="content" class="mw-body">
<header class="mw-body-header vector-page-titlebar">
<h1 id="firstHeading" class="firstHeading mw-first-heading"><span class="mw-page-title-main">Off-by-one-Error</span></h1>
</header>
<a id="top"></a>
<div id="bodyContent" class="vector-body ve-init-mw-desktopArticleTarget-targetContainer" aria-labelledby="firstHeading" data-mw-ve-target-container="">
<div id="contentSub">
<div id="mw-content-subtitle"></div>
</div>
<div id="mw-content-text" class="mw-body-content mw-content-ltr" lang="de" dir="ltr"><div class="mw-content-ltr mw-parser-output" lang="de" dir="ltr"><p>Ein <b>Off-by-one-Error</b> oder <b>Off-by-one-Fehler</b> (abgekürzt <b>OBOE</b>; deutsch etwa <i>Um-Eins-daneben-Fehler</i>),<sup id="cite_ref-1" class="reference"><a href="#cite_note-1"><span class="cite-bracket">[</span>1<span class="cite-bracket">]</span></a></sup> oder <i>Plus-minus-eins-Syndrom</i><sup id="cite_ref-2" class="reference"><a href="#cite_note-2"><span class="cite-bracket">[</span>2<span class="cite-bracket">]</span></a></sup> scherzhaft auch <i>„<a href="Figuren_aus_Star_Wars#Obi-Wan_Kenobi" title="Figuren aus Star Wars">Obi-Wan</a> error“</i>, da ähnlich klingend, oder <i>±1-Problem</i>, bezeichnet in der <a href="Informatik" title="Informatik">Informatik</a> einen Programmierfehler, bei dem eine Zahlenangabe oder eine Anzahl ausgeführter Schritte um 1 zu groß oder zu klein ist. Zum Beispiel ist die Größe eines Speicherblocks um 1 falsch oder es wird in einem <a href="Puffer_(Informatik)" title="Puffer (Informatik)">Puffer</a> um einen Schritt zu weit in den Speicher geschrieben, wobei der Speicher eines anderen Puffers bzw. einer Variable überschrieben wird.<sup id="cite_ref-3" class="reference"><a href="#cite_note-3"><span class="cite-bracket">[</span>3<span class="cite-bracket">]</span></a></sup>
</p>

<div class="mw-heading mw-heading2"><h2 id="Allgemeines">Allgemeines</h2></div>
<p>Off-by-one-Fehler ereignen sich oft im Umgang mit <a href="Datenfeld" title="Datenfeld">Datenfeldern</a>, <a href="Feld_(Datentyp)" class="mw-redirect" title="Feld (Datentyp)">Arrays</a>, <a href="Vektor" title="Vektor">Vektoren</a>, <a href="Liste_(Datenstruktur)" title="Liste (Datenstruktur)">Listen</a>, <a href="Zeichenkette" title="Zeichenkette">Zeichenketten</a> oder anderen indizierbaren <a href="Datentyp" title="Datentyp">Datentypen</a>.
</p><p>Off-by-one-Fehler können leicht unterlaufen und sind sehr schwer zu finden, vor allem, da sie sich sehr häufig nur unter ganz speziellen Bedingungen bemerkbar machen. Auch bei der Durchsicht des Quelltextes können sie sehr leicht übersehen werden. Erschwerend kommt hinzu, dass Indizes oder <a href="Speicheradresse#Segmentierte_Adressen" title="Speicheradresse">Offsets</a> im Quelltext meist durch Variablen oder Formeln gebildet werden. Maßnahmen von Compiler/Interpreter oder ggf. Betriebssystemen, die ein Überschreiten einer Puffergrenze um jedes einzelne Byte registrieren, greifen auch nur in dem Spezialfall, dass der gesamte reservierte Puffer genutzt werden soll.
</p><p>Wenn ein Off-by-one-Fehler gefunden und lokalisiert ist, ist er in der Regel sehr einfach zu beheben.
</p>
<div class="mw-heading mw-heading2"><h2 id="Häufige_Ursachen_(Auswahl)"><span id="H.C3.A4ufige_Ursachen_.28Auswahl.29"></span>Häufige Ursachen (Auswahl)</h2></div>
<p>Es gibt verschiedenste Fehlerursachen, die im Ergebnis zu einem Off-by-one-Fehler führen. Beispiele:
</p>
<ul><li>Eine häufige Fehlerquelle ist der Umstand, dass man bei der Programmierung das Indexieren häufig bei <a href="Null" title="Null">0</a> beginnt und nicht mit <a href="Eins" title="Eins">1</a> <i>(zero-based numbering)</i>. Bei einem Array mit 10 Datenfeldern bedeutet das, dass die Datenfelder nicht die <a href="Feld_(Datentyp)#Indizes" class="mw-redirect" title="Feld (Datentyp)">Indizes</a> 1 bis 10 haben, sondern die Indizes 0 bis 9. In einer Schleife „von 0 bis <i>Länge</i>“ wird somit auf ein elftes Element (Index 10) zugegriffen.</li></ul>
<dl><dd><table class="wikitable">
<tbody><tr>
<th>Element nach<br>umgangssprach-<br>licher Zählung
</th>
<th>Null-<br>basierte<br>Zählung
</th>
<th>Speicheradresse
</th></tr>
<tr>
<td>erstes Element</td>
<td>Element 0</td>
<td>Anfangsadresse + 0 × Größe des Elements
</td></tr>
<tr>
<td>zweites Element</td>
<td>Element 1</td>
<td>Anfangsadresse + 1 × Größe des Elements
</td></tr>
<tr>
<td>drittes Element</td>
<td>Element 2</td>
<td>Anfangsadresse + 2 × Größe des Elements
</td></tr>
<tr>
<td>viertes Element</td>
<td>Element 3</td>
<td>Anfangsadresse + 3 × Größe des Elements
</td></tr>
<tr>
<td>fünftes Element</td>
<td>Element 4</td>
<td>Anfangsadresse + 4 × Größe des Elements
</td></tr>
<tr>
<td>sechstes Element</td>
<td>Element 5</td>
<td>Anfangsadresse + 5 × Größe des Elements
</td></tr>
<tr>
<td>siebtes Element</td>
<td>Element 6</td>
<td>Anfangsadresse + 6 × Größe des Elements
</td></tr>
<tr>
<td>achtes Element</td>
<td>Element 7</td>
<td>Anfangsadresse + 7 × Größe des Elements
</td></tr>
<tr>
<td>neuntes Element</td>
<td>Element 8</td>
<td>Anfangsadresse + 8 × Größe des Elements
</td></tr>
<tr>
<td>zehntes Element</td>
<td>Element 9</td>
<td>Anfangsadresse + 9 × Größe des Elements
</td></tr>
<tr>
<td></td>
<td></td>
<td>Anfangsadresse +10 × Größe des Elements<br>gehört nicht mehr zum Array!
</td></tr></tbody></table></dd></dl>
<dl><dd>Die Verwirrung geht weiter durch unterschiedliche Handhabung in unterschiedlichen Programmiersprachen:
<dl><dd>Basic: <code>DIM A(10)</code> legt ein Array mit den Indices 0, 1, ..., 9, 10 an.</dd>
<dd>C/C++/Java/...: <code>a[10]</code> legt ein Array mit den Indices 0, 1, ..., 9 an.</dd>
<dd>Matlab: Eine Standard-Vektor <code>x = [10, 11, ... 19]</code>mit 10 Elementen verwendet die Indices 1, ..., 9, 10.</dd>
<dd>Matlab: <code>x = 0:10</code> verwendet die Indices 0, 1, ..., 9, 10.</dd>
<dd>Pascal: array <code>[0..10]</code> legt ein Array mit den Indices 0, 1, ..., 9, 10 an.</dd>
<dd>Pascal: array <code>[1..10]</code> legt ein Array mit den Indices 1, ..., 9, 10 an.</dd></dl></dd></dl>
<ul><li>Eine weitere häufige Fehlerquelle ist die Verwendung von <a href="Nullzeichen" title="Nullzeichen">Nullbytes</a>, vor allem bei Zeichenketten, also Text. Das Nullbyte ist ein in Text nicht vorkommendes Zeichen mit dem Wert 0 und markiert das Ende einer Zeichenkette, während der eigentliche Puffer für die Zeichenkette um ein Vielfaches größer sein kann. Dadurch muss man bei variablen Pufferinhalten die Puffergröße nicht ständig verändern und ebenso die Länge der Zeichenkette nicht separat angeben. Durch das Nullbyte ist eine Zeichenkette allerdings prinzipiell um ein Zeichen länger, als die Zeichenkette an sich lang ist. Beispielsweise ist die Zeichenkette „Hallo“ somit zwar 5 Zeichen lang, benötigt aber 6 Zeichen im Speicher. Funktionen, die die Länge einer Zeichenkette ermitteln und zurückgeben, zählen das Nullbyte nicht mit.</li>
<li>Off-by-one-Fehler treten auch häufig als Folge sogenannter <a href="Zaunpfahlfehler" title="Zaunpfahlfehler">Zaunpfahlfehler</a> auf, also durch die Verwechslung von Distanzen und Anzahlen bei der Indizierung.</li>
<li>Falls gar nichts zu tun ist, z. B. bei Analyse einer leeren Zeichenkette, wird eine <a href="Schleife_(Programmierung)#Arten" title="Schleife (Programmierung)">nachprüfende Schleife</a> einmal (also einmal zu oft) ausgeführt.</li></ul>
<div class="mw-heading mw-heading2"><h2 id="Folgen">Folgen</h2></div>
<p>Im Falle eines Off-by-one-Errors wird typischerweise beim Schreiben der Schleife, die ein Feld verarbeiten soll, die Abbruch- bzw. Fortsetzungsbedingung falsch gewählt, sodass im Rumpf der Schleife eine Anweisung, die indexbasiert auf das Feld zugreift, genau einmal zu oft oder einmal zu wenig ausgeführt wird, wodurch entweder versucht wird, auf ein Element des Feldes zuzugreifen, das nicht existiert, oder das letzte (bzw. erste) Element des Feldes ausgelassen wird. Im erstgenannten Fall ist oft ein Index-out-of-upper-Range-Fehler (o. ä.) die auffällige Folge, im letztgenannten Fall wird mitunter gar kein Fehler sichtbar, solange nicht die gesamte Puffergröße genutzt werden soll oder ein Index-out-of-lower-Range-Fehler gemeldet wird.
</p><p>Ein Off-by-one-Fehler kann durchaus zu einem <a href="Absturz_(Computer)" title="Absturz (Computer)">Absturz</a> des Programms führen, wenn im Speicher nach dem Puffer wichtige Daten liegen, die von der Schleife dann überschrieben werden (z. B. <a href="Zeiger_(Informatik)" title="Zeiger (Informatik)">Zeiger</a> auf eine Struktur). Grundsätzlich kann nach einem Puffer im Arbeitsspeicher auch Programmcode liegen, wobei in der Regel ein zufälliges Überschreiben ebenfalls einen Programmabsturz verursacht, da die Daten keinem gültigen Maschinenbefehl entsprechen.
</p>
<div class="mw-heading mw-heading2"><h2 id="Beispiele">Beispiele</h2></div>
<p>Beispiel aus der Sprache <a href="C_(Programmiersprache)" title="C (Programmiersprache)">C</a>:
</p>
<div class="mw-highlight mw-highlight-lang-c mw-content-ltr" dir="ltr"><pre><span></span><span class="cp">#define ANZAHL 10</span>

<span class="kt">double</span><span class="w"> </span><span class="n">nettopreise</span><span class="w"> </span><span class="p">[</span><span class="n">ANZAHL</span><span class="p">];</span>
<span class="kt">double</span><span class="w"> </span><span class="n">bruttopreise</span><span class="p">[</span><span class="n">ANZAHL</span><span class="p">];</span>

<span class="cm">/* nettopreise initialisieren */</span>
<span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="p">;</span>
<span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="n">ANZAHL</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span>
<span class="w"> </span><span class="n">bruttopreise</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">nettopreise</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">1.19</span><span class="p">;</span><span class="w"> </span><span class="c1">// MwSt aufschlagen.</span>
</pre></div>
<p>In diesem Fall müsste es <code>i &lt; ANZAHL</code> oder <code>i+1 &lt;= ANZAHL</code><sup id="cite_ref-4" class="reference"><a href="#cite_note-4"><span class="cite-bracket">[</span>4<span class="cite-bracket">]</span></a></sup> und nicht <code>i &lt;= ANZAHL</code> heißen, da in der Deklaration zwar <code>ANZAHL</code> als Feldgröße angegeben wurde, aber der maximale Index <code>ANZAHL-1</code> ist.
</p><p>Häufig resultiert diese Art der Fehler aus der Verwirrung, die dadurch entsteht, dass Menschen von 1 bis&nbsp;N zählen, Feldindizes in vielen Programmiersprachen aber von 0 bis&nbsp;N−1 gehen.<sup id="cite_ref-5" class="reference"><a href="#cite_note-5"><span class="cite-bracket">[</span>5<span class="cite-bracket">]</span></a></sup> Dann gibt es auch noch das Größer-als-Zeichen und das Größer-gleich-Zeichen, die man verwechseln kann. Darüber hinaus kann die Abbruchbedingung komplizierter ausfallen, so dass sich an dieser Stelle häufig Off-by-one-Fehler ergeben.
</p><p>Besonders tückisch ist der Fall einer Datenstruktur, die doch mit 1 beginnt, jedoch Schleifenzählungen über diese Datenstruktur mit 0 beginnen.
</p><p>Ebenfalls kann leicht ein Off-by-one-Fehler unterlaufen, wenn bei <a href="Infimum_und_Supremum" title="Infimum und Supremum">Bereichsgrenzen</a> nicht beachtet wird, ob die untere und obere Schranke einschließend oder ausschließend sind. So liefert die Funktion <code>substring</code> in <a href="Java_(Programmiersprache)" title="Java (Programmiersprache)">Java</a> den Teil eines Strings, der die untere Schranke mit einschließt, die obere aber nicht.
</p>
<div class="mw-highlight mw-highlight-lang-java mw-content-ltr" dir="ltr"><pre><span></span><span class="n">String</span><span class="w"> </span><span class="n">wort</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"Foobar"</span><span class="p">;</span>
<span class="n">String</span><span class="w"> </span><span class="n">zweiteSilbe</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">wort</span><span class="p">.</span><span class="na">substring</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">5</span><span class="p">);</span><span class="w"> </span><span class="c1">// schlägt fehl</span>
</pre></div>
<p>Will man beispielsweise aus dem Wort „Foobar“ das Teilwort „bar“ herauslösen, indem man die Buchstaben durchzählt, so kann man sich bei der oberen Schranke leicht vertun, selbst wenn man korrekt bei 0 zu zählen beginnt. Da das Wort „bar“ die Buchstaben bei den Indizes 3, 4 und 5 umfasst, ist man versucht, <code>substring(3, 5)</code> aufzurufen. Als Ergebnis würde man aber nur „ba“ erhalten.
</p><p>Um dieses Problem zu vermeiden, benutzen andere Programmiersprachen wie C/C++, JavaScript oder PHP anstelle der Parameter Start-Index und End-Index, die Parameter Start-Index und Länge der gewünschten Zeichenkette.
</p>
<div class="mw-heading mw-heading2"><h2 id="Weblinks">Weblinks</h2></div>
<ul><li><a rel="nofollow" class="external text" href="http://foldoc.org/off-by-one+errors">off-by-one error</a> im <a href="FOLDOC" class="mw-redirect" title="FOLDOC">Free On-line Dictionary of Computing</a> (englisch)</li></ul>
<div class="mw-heading mw-heading2"><h2 id="Einzelnachweise">Einzelnachweise</h2></div>
<ol class="references">
<li id="cite_note-1"><span class="mw-cite-backlink"><a href="#cite_ref-1">↑</a></span> <span class="reference-text"><a rel="nofollow" class="external text" href="http://userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/formal_bereich_de">userpage.fu-berlin.de</a></span>
</li>
<li id="cite_note-2"><span class="mw-cite-backlink"><a href="#cite_ref-2">↑</a></span> <span class="reference-text">Ägidius Plüss: <a rel="nofollow" class="external text" href="http://books.google.de/books?id=b-HMaUG1ct0C&amp;pg=PA51"><i>Java – exemplarisch: learning by doing</i>.</a> Oldenbourg Wissenschaftsverlag, 2004, ISBN 3-486-20040-2, S. 51.</span>
</li>
<li id="cite_note-3"><span class="mw-cite-backlink"><a href="#cite_ref-3">↑</a></span> <span class="reference-text"><a rel="nofollow" class="external text" href="http://foldoc.org/off-by-one+errors">foldoc.org</a></span>
</li>
<li id="cite_note-4"><span class="mw-cite-backlink"><a href="#cite_ref-4">↑</a></span> <span class="reference-text">Never ever ever use <code>size_t i; i &lt;= ANZAHL-1</code>, diese Art von Code ist zwar extrem verbreitet, aber auch ein Geschenk für jeden, der in einen Computer einbrechen will. Man muss irgendwo ein leeres Array einschmuggeln.</span>
</li>
<li id="cite_note-5"><span class="mw-cite-backlink"><a href="#cite_ref-5">↑</a></span> <span class="reference-text">Dieter Masak: <a rel="nofollow" class="external text" href="http://books.google.de/books?id=_ADkwozCvegC&amp;pg=PA161"><i>Legacysoftware: Das lange Leben der Altsysteme</i>.</a> Springer-Verlag, 2005, ISBN 3-540-25412-9, S.&nbsp;161.</span>
</li>
</ol></div><!--htdig_noindex--><div><div class="zim-footer">
Dieser Artikel wurde von <a class="external text" title="Zuletzt bearbeitet am 2024-11-12" href="https://de.wikipedia.org/wiki/?title=Off-by-one-Error&amp;oldid=250273285">Wikipedia</a> herausgegeben. Der Text ist unter <a class="external text" href="https://creativecommons.org/licenses/by-sa/4.0/deed.de">Creative Commons Attribution-Share Alike 4.0</a> verfügbar, sofern nicht anders angegeben. Für die Mediendateien können zusätzliche Bedingungen gelten.
</div>
</div><!--/htdig_noindex--></div>
</div>
</main>
</div>
</div>
</div>
<script src="./_webp_/webpHandler.js"></script>

</body></html>